package sketch;

import java.util.LinkedList;
import java.util.List;

import sketch.ast.MethodDeclarationWithHoles;
import sketch.util.Checker;
import sketch.util.Globals;

/**
 * This class mimics the sequence created
 * currently for testing purpose
 * 
 * */
public class SketchSequence {
	
	public static final String RECEIVER = "%RECEIVER%";
	
	public MethodDeclarationWithHoles methodWithHoles = null;
	
	/**
	 * The real sequence in randoop
	 * */
	//public final Sequence sequence;
	
	public SketchSequence() {
		//this.sequence = new Sequence();
	}
	
	public final List<ExecutableSequenceContent[]> contents = new LinkedList<ExecutableSequenceContent[]>();
	
	public void renameTest(String name) {
		Checker.checkNull(name, "The new name of test should not be null!");
		Checker.checkNull(this.methodWithHoles, "The method with holes object should not be null!");
		this.methodWithHoles.rename(name);
	}
	
	public void setExecutableSequenceContent(List<ExecutableSequenceContent[]> list) {
		Checker.checkNull(list, "The list of executable sequence content should not be null.");
		this.contents.clear();
		for(ExecutableSequenceContent[] listElement : list) {
			addExecutableContent(listElement);
		}
	}
	
	public void setMethodDeclarationWithHoles(MethodDeclarationWithHoles methodWithHoles) {
		Checker.checkNull(methodWithHoles, "The mthodWithHoles argument could not be null!");
		this.methodWithHoles = methodWithHoles;
	}
	
	//fill in holes
	public void fillinHoles(Class<?>[] generatorTypes) {
		Checker.checkNull(this.methodWithHoles, "You should set MethodDeclarationWithHoles first!");
		Checker.checkNull(generatorTypes, "The generator type array should not be null!");
		
//		System.out.println("start filling the holes");
		for(ExecutableSequenceContent[] listcontent : contents) {
//			for(ExecutableSequenceContent c : listcontent) {
//				System.out.println(c);
//			}
//			System.out.println();
		}
		this.methodWithHoles.fillinHoles(contents, generatorTypes);
	}
	
	public String outputGeneratedTestMethod() {
		return this.methodWithHoles.toString();
	}
	
	//add a new contents
	public void addExecutableContent(ExecutableSequenceContent[] contents) {
		Checker.checkNull(contents, "The executable content input could not be null!");
		this.contents.add(contents);
	}
	
	public List<ExecutableSequenceContent[]> getExecutableContents() {
		return this.contents;
	}
	
	/**
	 * This is just for mocking purpose
	 * */
	public final List<String> sequences = new LinkedList<String>();
	
	public void addText(String seq) {
		sequences.add(seq);
	}
	
//	public static SketchSequence emptySequence() {
//		return new SketchSequence();
//	}
	
	public SketchSequence repeatAll(int i) {
		Checker.checkTrue( i >= 1, "Can not repeat less than once!");
		if(sequences.isEmpty()) {
			return this;
		}
		String[] currentSequences = (String[])(this.sequences.toArray(new String[0]));
		while(i-- > 0) {
			for(String currentSequence : currentSequences) {
			    sequences.add(currentSequence);
			}
		}
		return this;
	}
	
	public SketchSequence appendText(SketchSequence s) {
		for(String seq : s.sequences) {
			sequences.add(seq);
		}
		return this;
	}
	
//	public SketchSequence addRegressionObservations() {
//		SketchSequence sequence = new SketchSequence();
//		for(String seq : this.sequences) {
//			sequence.addText("assertEquals(" + seq + ");");
//		}
//		sequences.clear();
//		for(String seq : sequence.sequences) {
//			this.sequences.add(seq);
//		}
//		return this;
//	}
	
//	public String seeExecutionResults() {
//		this.checkValidity();
//		StringBuilder sb = new StringBuilder();
//		for(ExecutableSequenceContent content : this.contents) {
//			sb.append(content);
//			sb.append(Globals.lineSep);
//		}
//		return sb.toString();
//	}
	
	private void checkValidity () {
		//nothing now
	}
	
	public String toCodeString() {
		throw new UnsupportedOperationException("Method toCodeString() is not supported yet!");
	}
	
	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder();
		for(String seq : sequences) {
			sb.append(seq);
			sb.append(Globals.lineSep);
		}
		return sb.toString();
	}
	
}
